#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
#include <assert.h>
#include <sstream>
#include <cgi_control.h>
#include <Singleton.h>
#include <memcheck.h>
#include <log.h>
#include <http_decoder.h>
#include <keydic.h>

using namespace std;

HTTP_SVR_NS_BEGIN

int         TCGIControl::_nCgiCount     = 0;
TCGIInfo*   TCGIControl::_stCgiList     = NULL;

struct proxy_mrec {
    int gzippable;
    const char ext[8];
    const char *mime;
    //struct mrec *next;
};

 static struct proxy_mrec proxy_mimetypes[] = {
    { 1, "ai\0",  "application/postscript" },
    { 0, "ace",   "application/octet-stream" },
    { 1, "aif",   "audio/x-aiff" },
    { 1, "aifc",  "audio/x-aiff" },
    { 1, "aiff",  "audio/x-aiff" },
    { 2, "asc",   "text/plain" },
    { 0, "asf",   "video/x-ms-asf" },
    { 1, "au\0",  "audio/basic" },
    { 0, "avi",   "video/x-msvideo" },
    { 1, "bcpio", "application/x-bcpio" },
    { 1, "bin",   "application/octet-stream" },
    { 1, "bmp",   "image/bmp" },
    { 0, "bz2",   "application/x-bzip2" },
    { 0, "cab",   "application/octet-stream" },
    { 1, "cdf",   "application/x-netcdf" },
    { 1, "cgm",   "image/cgm" },
    { 1, "class", "application/octet-stream" },
    { 1, "cpio" , "application/x-cpio" },
    { 1, "cpt",   "application/mac-compactpro" },
    { 0, "cpz",   "application/x-gzip" },
    { 2, "csh",   "application/x-csh" },
    { 2, "css",   "text/css" },
    { 2, "csv",   "text/plain" },
    { 1, "dcr",   "application/x-director" },
    { 1, "dir",   "application/x-director" },
    { 1, "djv",   "image/vnd.djvu" },
    { 1, "djvu",  "image/vnd.djvu" },
    { 1, "dll",   "application/octet-stream" },
    { 1, "dl_",   "application/octet-stream" },
    { 1, "dmg",   "application/octet-stream" },
    { 1, "dms",   "application/octet-stream" },
    { 2, "doc",   "application/msword" },
    { 1, "dtd",   "application/xml-dtd" },
    { 1, "dvi",   "application/x-dvi" },
    { 1, "dxr",   "application/x-director" },
    { 2, "eml",   "message/rfc822" },
    { 1, "eps",   "application/postscript" },
    { 2, "etx",   "text/x-setext" },
    { 1, "exe",   "application/octet-stream" },
    { 1, "ex_",   "application/octet-stream" },
    { 1, "ez\0",  "application/andrew-inset" },
    { 0, "gif",   "image/gif" },
    { 1, "gram",  "application/srgs" },
    { 1, "grxml", "application/srgs+xml" },
    { 1, "gtar",  "application/x-gtar" },
    { 0, "gz\0",  "application/x-gzip" },
    { 1, "hdf",   "application/x-hdf" },
    { 2, "htc",   "text/plain" },
    { 1, "hqx",   "application/mac-binhex40" },
    { 2, "htm",   "text/html" },
    { 2, "html",  "text/html" },
    { 1, "ice",   "x-conference/x-cooltalk" },
    { 2, "ico",   "image/x-icon" },
    { 2, "ics",   "text/calendar" },
    { 1, "ief",   "image/ief" },
    { 2, "ifb",   "text/calendar" },
    { 1, "iges",  "model/iges" },
    { 1, "igs",   "model/iges" },
    { 0, "jpe",   "image/jpeg" },
    { 0, "jpeg",  "image/jpeg" },
    { 0, "jpg",   "image/jpeg" },
    { 2, "js\0",  "application/x-javascript" },
    { 0, "kar",   "audio/midi" },
    { 1, "latex", "application/x-latex" },
    { 0, "lha",   "application/octet-stream" },
    { 0, "lzh",   "application/octet-stream" },
    { 2, "m3u",   "audio/x-mpegurl" },
    { 2, "m4u",   "video/vnd.mpegurl" },
    { 1, "man",   "application/x-troff-man" },
    { 2, "mathml","application/mathml+xml" },
    { 1, "me\0",  "application/x-troff-me" },
    { 1, "mesh",  "model/mesh" },
    { 2, "mht",   "message/rfc822" },
    { 2, "mhtml", "message/rfc822" },
    { 0, "mid",   "audio/midi" },
    { 0, "midi",  "audio/midi" },
    { 1, "mif",   "application/vnd.mif" },
    { 0, "mov",   "video/quicktime" },
    { 0, "movie", "video/x-sgi-movie" },
    { 0, "mp2",   "audio/mpeg" },
    { 0, "mp3",   "audio/mpeg" },
    { 0, "mp4",   "video/mpeg" },
    { 0, "mpe",   "video/mpeg" },
    { 0, "mpeg",  "video/mpeg" },
    { 0, "mpg",   "video/mpeg" },
    { 0, "mpga",  "audio/mpeg" },
    { 1, "ms\0",  "application/x-troff-ms" },
    { 1, "msh",   "model/mesh" },
    { 0, "mxu",   "video/vnd.mpegurl" },
    { 1, "nc\0",  "application/x-netcdf" },
    { 1, "oda",   "application/oda" },
    { 0, "ogg",   "application/ogg" },
    { 1, "pbm",   "image/x-portable-bitmap" },
    { 1, "pdb",   "chemical/x-pdb" },
    { 1, "pdf",   "application/pdf" },
    { 1, "pgm",   "image/x-portable-graymap" },
    { 1, "pgn",   "application/x-chess-pgn" },
    { 2, "phtml", "text/html" },
    { 0, "png",   "image/png" },
    { 1, "pnm",   "image/x-portable-anymap" },
    { 1, "ppm",   "image/x-portable-pixmap" },
    { 1, "ppt",   "application/vnd.ms-powerpoint" },
    { 2, "ps\0",  "application/postscript" },
    { 0, "qt\0",  "video/quicktime" },
    { 0, "ra\0",  "audio/x-pn-realaudio" },
    { 1, "ram",   "audio/x-pn-realaudio" },
    { 0, "rar",   "application/x-rar" },
    { 1, "ras",   "image/x-cmu-raster" },
    { 2, "rdf",   "application/rdf+xml" },
    { 1, "rgb",   "image/x-rgb" },
    { 0, "rm\0",  "application/vnd.rn-realmedia" },
    { 0, "rmvb",  "application/vnd.rn-realmedia" },
    { 1, "roff",  "application/x-troff" },
    { 2, "rtf",   "text/rtf" },
    { 2, "rtx",   "text/richtext" },
    { 2, "sgm",   "text/sgml" },
    { 2, "sgml",  "text/sgml" },
    { 2, "sh\0",  "application/x-sh" },
    { 2, "shar",  "application/x-shar" },
    { 2, "shtml", "text/html" },
    { 1, "silo",  "model/mesh" },
    { 1, "sit",   "application/x-stuffit" },
    { 1, "skd",   "application/x-koan" },
    { 1, "skm",   "application/x-koan" },
    { 1, "skp",   "application/x-koan" },
    { 1, "skt",   "application/x-koan" },
    { 1, "smi",   "application/smil" },
    { 1, "smil",  "application/smil" },
    { 1, "snd",   "audio/basic" },
    { 1, "so\0",  "application/octet-stream" },
    { 1, "spl",   "application/x-futuresplash" },
    { 1, "src",   "application/x-wais-source" },
    { 1, "sv4cpio","application/x-sv4cpio" },
    { 1, "sv4crc","application/x-sv4crc" },
    { 1, "svg",   "image/svg+xml" },
    { 1, "swf",   "application/x-shockwave-flash" },
    { 1, "t\0\0", "application/x-troff" },
    { 1, "tar",   "application/x-tar" },
    { 0, "tbz",   "application/x-bzip2" },
    { 0, "tbz2",  "application/x-bzip2" },
    { 1, "tcl",   "application/x-tcl" },
    { 1, "tex",   "application/x-tex" },
    { 1, "texi",  "application/x-texinfo" },
    { 1, "texinfo","application/x-texinfo" },
    { 0, "tgz",   "application/x-gzip" },
    { 0, "tz\0",  "application/x-compress" },
    { 0, "tif",   "image/tiff" },
    { 0, "tiff",  "image/tiff" },
    { 1, "tr\0",  "application/x-troff" },
    { 2, "tsv",   "text/tab-separated-values" },
    { 2, "txt",   "text/plain" },
    { 1, "ustar", "application/x-ustar" },
    { 2, "vbs",   "text/plain" },
    { 1, "vcd",   "application/x-cdlink" },
    { 0, "vob",   "video/mpeg" },
    { 1, "vrml",  "model/vrml" },
    { 1, "vxml",  "application/voicexml+xml" },
    { 1, "wav",   "audio/x-wav" },
    { 1, "wbmp",  "image/vnd.wap.wbmp" },
    { 1, "wbxml", "application/vnd.wap.wbxml" },
    { 0, "wma",   "audio/x-ms-wma" },
    { 2, "wml",   "text/vnd.wap.wml" },
    { 1, "wmlc",  "application/vnd.wap.wmlc" },
    { 2, "wmls",  "text/vnd.wap.wmlscript" },
    { 1, "wmlsc", "application/vnd.wap.wmlscriptc" },
    { 0, "wmv",   "video/x-ms-wmv" },
    { 1, "wrl",   "model/vrml" },
    { 2, "xbm",   "image/x-xbitmap" },
    { 2, "xht",   "application/xhtml+xml" },
    { 2, "xhtml", "application/xhtml+xml" },
    { 2, "xls",   "application/vnd.ms-excel" },
    { 2, "xml",   "application/xml" },
    { 2, "xpm",   "image/x-xpixmap" },
    { 2, "xsl",   "application/xml" },
    { 2, "xslt",  "application/xslt+xml" },
    { 2, "xul",   "application/vnd.mozilla.xul+xml" },
    { 1, "xwd",   "image/x-xwindowdump" },
    { 1, "xyz",   "chemical/x-xyz" },
    { 0, "z\0\0", "application/x-compress" },
    { 0, "zip",   "application/zip" },
};



static int last_mod_cmp(const char* src_filepath, const char* dst_filepath)
{
    struct stat stBuf1, stBuf2;
    if(stat(src_filepath, &stBuf1) == 0 && stat(dst_filepath, &stBuf2) == 0)
    {
        //compare the last modified time
        if(stBuf1.st_mtime == stBuf2.st_mtime)
            return 0;
    }
    
    return -1;
}

int get_mime_type(const char* filename,  char* mime, int& zip)
{
    const char* tempext = filename;
    const char* ext = NULL;
   char gzipfilename[1024];
	
    while((tempext = strstr(tempext, ".")))
    	{
    	    ext = tempext++;
    	}
	
    if(!ext)
		return -1;
		

	 sprintf(gzipfilename, "%s.tgz", filename);
	 if(last_mod_cmp(gzipfilename,filename )==0)
	 	{
	 	    zip = 1;
	 	}

	  ext++;
	
    for(int i=0; i<(int)(sizeof(proxy_mimetypes)/sizeof(*proxy_mimetypes)); i++)
    {
        if(strcmp(ext, proxy_mimetypes[i].ext) == 0)
        {
          
            strcpy(mime,proxy_mimetypes[i].mime);

            return 0;
        }
    }
    
    return -1;
}


TCGIControl::TCGIControl (void) : 
_stCgiDics (NULL),
_pCgiSwitch (NULL)
{
}

TCGIControl::~TCGIControl (void)
{
    FREE_CLEAR(_stCgiList);
    
    CSingleton<TCGIInfo>::Destroy();
}

TCGIControl* TCGIControl::Instance (void)
{
    return CSingleton<TCGIControl>::Instance ();
}

void TCGIControl::Destroy (void)
{
    return CSingleton<TCGIControl>::Destroy ();
}

int TCGIControl::open (const char* xmlfile)
{
    CMarkupSTL  markup;

	//this is important
	_nCgiCount=0;

    if(NULL == _stCgiDics)
    {
        _stCgiDics = CSingleton<TCGIInfoDic>::Instance ();
        if (NULL == _stCgiDics)
        {
            log_boot ("create cgi info dictionary failed.");
            return -1;
        }
    }
    else
    {
        _stCgiDics->release_items();
    }
    
    //init cgi info dictionary for no case
    if (_stCgiDics->init_root(1) != 0)
    {
        log_boot ("init url dictionary failed.");
        return -1;
    }
    
    if(NULL == _stCgiList)
    {
        //create cgi info list
        _stCgiList = (TCGIInfo*) MALLOC (MAX_CGI_COUNT * sizeof(TCGIInfo));
        if (NULL == _stCgiList)
        {
            log_boot ("create cgi info list failed, msg[%s]", strerror(errno));
            return -1;
        }
    }

    memset (_stCgiList, 0x00, MAX_CGI_COUNT * sizeof(TCGIInfo));

	if(!markup.Load(xmlfile))
	{	
		log_boot ("Load xml %s failed", xmlfile);
		return -1;
	}

    if(!markup.FindElem("SYSTEM"))
	{
		log_boot ("Can not FindElem [SYSTEM] in xml %s failed\n", xmlfile);
		return -1;
	}

    if (!markup.IntoElem())
    {
        log_boot ("invoke IntoElem() failed.");
        return -1;
    } 

    markup.IntoElem();

	markup.OutOfElem();

	if (_nCgiCount <= 0)
	{
			log_boot ("valid cgi info no found, cgi count[%d]", _nCgiCount);
			return -1;
	}



	CMarkupSTL markup1;
	if(!markup1.Load(xmlfile))
	{	
			log_boot ("Load xml %s failed", xmlfile);
			return -1;
	}
	if(!markup1.FindElem("SYSTEM"))
	{
			log_boot ("Can not FindElem [SYSTEM] in xml %s failed\n", xmlfile);
			return -1;
	}

	if (!markup1.IntoElem())
	{
			log_boot ("invoke IntoElem() failed.");
			return -1;
	} 



	return 0;
}

HTTP_SVR_NS_END

